package com.xxx.gateway.configure;

import com.alibaba.fastjson2.JSON;
import com.xxx.common.base.constants.MdcKey;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.UUID;

@Component
@Slf4j
public class LogFilter implements GlobalFilter, Ordered {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 生成唯一 traceId
        String traceId = UUID.randomUUID().toString().replace("-", "");
        exchange.getRequest().mutate().header(MdcKey.TRACE_ID, traceId);
        MDC.put(MdcKey.TRACE_ID, traceId);

        // 打印请求信息
        ServerHttpRequest request = exchange.getRequest();
        log.debug("========== Request Info ==========");
        log.debug("Request Method: {}", request.getMethod());
        log.debug("Request Path: {}", request.getPath());
        log.debug("Request Headers: {}", request.getHeaders());
        log.debug("Request Query Params: {}", request.getQueryParams());

        // 如果存在请求体，读取并记录
        if (request.getHeaders().getContentLength() > 0) {
            return DataBufferUtils.join(request.getBody())
                    .flatMap(dataBuffer -> {
                        try {
                            // 1. 读取请求体内容
                            byte[] bytes = new byte[dataBuffer.readableByteCount()];
                            dataBuffer.read(bytes);
                            DataBufferUtils.release(dataBuffer);

                            // 2. 打印请求体
                            String body = new String(bytes, StandardCharsets.UTF_8);
                            log.debug("Request Body: {}", JSON.parse(body));

                            // 3. 通过装饰器重建请求体
                            DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();
                            DataBuffer newBuffer = bufferFactory.wrap(bytes);
                            ServerHttpRequestDecorator newRequest = new ServerHttpRequestDecorator(request) {
                                @Override
                                public Flux<DataBuffer> getBody() {
                                    return Flux.just(newBuffer);
                                }
                            };

                            // 4. 传递装饰后的请求
                            return chain.filter(exchange.mutate().request(newRequest).build())
                                    .then(Mono.fromRunnable(() -> {
                                        logResponseInfo(exchange);
                                    }));
                        } catch (Exception e) {
                            DataBufferUtils.release(dataBuffer);
                            return Mono.error(e);
                        }
                    });
        } else {
            return chain.filter(exchange)
                    .then(Mono.fromRunnable(() -> {
                        logResponseInfo(exchange);
                    }));
        }

    }

    /*** 打印响应信息 */
    private static void logResponseInfo(ServerWebExchange exchange) {
        // 打印响应信息
        ServerHttpResponse response = exchange.getResponse();
        log.debug("========== Response Info ==========");
        log.debug("Response Status: {}", response.getStatusCode());
        log.debug("Response Headers: {}", response.getHeaders());
    }

    @Override
    public int getOrder() {
        return -1; // 过滤器的执行顺序，值越小优先级越高
    }
}